package treinadores;

import java.util.ArrayList;
import java.util.Arrays;

import org.neuroph.core.learning.SupervisedTrainingElement;
import org.neuroph.core.learning.TrainingSet;
import org.neuroph.nnet.MultiLayerPerceptron;
import org.neuroph.nnet.learning.DynamicBackPropagation;

import interfaces.ITreinadorRN;

public class TreinadorPermanecer implements ITreinadorRN {

	
	/**
	 * Número de entradas para a rede neural
	 */
	int numeroDeEntradas = 5;
	/**
	 * Número de saídas para a rede neural
	 */
	int numeroDeSaidas = 4;
	/**
	 * Arquivo correspondente a rede neural
	 */
    String MLP_FILE = "permanecer.nnet";
    /**
     * Nome do arquivo de testes
     */
    String TS_FILE = "permanecer.set";
    /**
     * Conjunto de treinamento com 5 campos de entrada (vide problema) e 2 campos de saida
     * 
     * 5 Entradas: 1 para a bola, 3 para os jogadores e 1 para saída
     */
    TrainingSet training = new TrainingSet(numeroDeEntradas,numeroDeSaidas);
    /**
     * Classe necessária para realizar o backpropagation
     */
    DynamicBackPropagation learning;
    /**
     * MultilayerPerceptron ou rede neural
     */
    MultiLayerPerceptron mlp;

   /**
    * Cria uma rede neural para testes
    * O conteúdo dela é salvo em um arquivo
   */
    public TreinadorPermanecer()
    {
    	//necessário para realizar o backPropagation
    	learning = new DynamicBackPropagation();
        learning.setMaxIterations(500);
        learning.setLearningRate(0.7);
        //Número de camadas
        ArrayList<Integer> camadas = new ArrayList<Integer>();
        //camada 1 : 2 neuronios
        camadas.add(numeroDeEntradas);
        //Camada 2 : 12 neuronios
        camadas.add(12);
        //Camada 3 : 2 neuronios
        camadas.add(numeroDeSaidas);
        //Cria um perceptron
        mlp = new MultiLayerPerceptron (camadas);
        //adiciona as entradas de treinamento
        adicionaEntradasDeTreinamento();
    }
    
    /**
	 * Adiciona entradas para fazer o treinamento
	 */
	public void adicionaEntradasDeTreinamento(){
    	//aqui são adicionadas algumas entradas aleatórias e calculadas algumas saídas
    	//Algoritmo preliminar de treinamento, não sei se vai ficar satisfatório
    	//o bastante.
    	//A RN funciona para cada jogador
    	//O treinamento tenta elimiar redundâncias de posições iguais de jogadores
    	
    	for(int posicaoJogadorNossoTime = 0; posicaoJogadorNossoTime <= 15; posicaoJogadorNossoTime++){
	        for(int posicaoJogadorAdversario1 = 0; posicaoJogadorAdversario1 <= 15; posicaoJogadorAdversario1++){
	        	for(int posicaoJogadorAdversario2 = 1; posicaoJogadorAdversario2 <= 15; posicaoJogadorAdversario2 += 4)
	        	{
	        		for(int posicaoJogadorAdversario3 = 2; posicaoJogadorAdversario3 <= 15; posicaoJogadorAdversario3 += 4)
	            	{
	        			for(int posicaoJogadorAdversario4 = 3; posicaoJogadorAdversario4 <= 15; posicaoJogadorAdversario4 += 4)
	                	{
	        			    
//	                    	  double adiciona = Math.random();
//	                    	  
//	                    	  if(adiciona < 0.1)
//	                    	  {
	                    		  int [] jogadores = {posicaoJogadorNossoTime,
	                    				  posicaoJogadorAdversario1,posicaoJogadorAdversario2,
	                    				  posicaoJogadorAdversario3
	                    				  ,posicaoJogadorAdversario4};
	                    		  
	                    		  double [] saidaDesejada = CalculosAuxiliares.getSaidaDesejadaPermanecer(posicaoJogadorNossoTime,
	                    				  Arrays.copyOfRange(jogadores, 1, jogadores.length));
	                    		  training.addElement(new SupervisedTrainingElement(
	                    				  //entrada
	                    				  new double[] {posicaoJogadorNossoTime,
	                    				  posicaoJogadorAdversario1,posicaoJogadorAdversario2,posicaoJogadorAdversario3,
	                    				  posicaoJogadorAdversario4},
	                    				  //saida
	                    				  saidaDesejada));
//	                    	  }
	                	}
	            	}
	        	}
	    	}
    	}
    }

	
    
    /**
     * Treina a rede e salva no arquivo do conjunto de treinamento
     */
    public void treinarRede(){
    	//Treina a rede!
    	mlp.learnInSameThread(training, learning);
    }    
	
	@Override
	public void treinar() {
        //treina a rede
        treinarRede();
        //salvando arquivos
        mlp.save(MLP_FILE);
        training.save(TS_FILE);
	}

}
